home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / sbin / ndiswrapper-1.9 < prev    next >
Text File  |  2009-04-30  |  27KB  |  1,028 lines

  1. #!/usr/bin/perl
  2.  
  3. #/*
  4. #*  Copyright (C) 2005-2006 Pontus Fuchs, Giridhar Pemmasani
  5. #*
  6. #*
  7. #*  This program is free software; you can redistribute it and/or modify
  8. #*  it under the terms of the GNU General Public License as published by
  9. #*  the Free Software Foundation; either version 2 of the License, or
  10. #*  (at your option) any later version.
  11. #*
  12. #*  This program is distributed in the hope that it will be useful,
  13. #*  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. #*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. #*  GNU General Public License for more details.
  16. #*
  17. #*/
  18.  
  19. use strict;
  20. use Fcntl ':mode';
  21. use File::Basename;
  22. use File::Copy;
  23. use File::Path;
  24. use Cwd;
  25.  
  26. $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}";
  27.  
  28. my $WRAP_PCI_BUS = 5;
  29. my $WRAP_PCMCIA_BUS = 8;
  30. my $WRAP_USB_BUS = 15;
  31.  
  32. my %sections;
  33. my %parsed_sections;
  34. my $confdir = "/etc/ndiswrapper";
  35. my $src_dir;
  36. my $driver_name;
  37. my @source_disks_files;
  38.  
  39. my $re_dev_id = "([[:xdigit:]]{4})";
  40. my $re_sub_dev_conf = "$re_dev_id:$re_dev_id:$re_dev_id:$re_dev_id" .
  41.   "\.([[:xdigit:]]+)\.conf";
  42. my $re_dev_conf = "$re_dev_id:$re_dev_id\.([[:xdigit:]]+)\.conf";
  43.  
  44. # fixup list for parameters.
  45. my %param_fixlist = ("EnableRadio|0" => "1",
  46.              "IBSSGMode|0" => "2",
  47.              "PrivacyMode|0" => "2",
  48.              "MapRegisters|256" => "64",
  49.              "AdhocGMode|1" => "0");
  50.  
  51. if (@ARGV < 1) {
  52.     usage();
  53.     exit(1);
  54. }
  55.  
  56. my $modconf;
  57. if (`uname -r` =~ /(\d+)\.(\d+)\.(\d+)/) {
  58.     if ($2 > 4) {
  59.     if (-d "/etc/modprobe.d") {
  60.         $modconf = "/etc/modprobe.d/ndiswrapper";
  61.     } else {
  62.         $modconf = "/etc/modprobe.conf";
  63.     }
  64.     } else {
  65.     if (-d "/etc/modutils") {
  66.         $modconf = "/etc/modutils/ndiswrapper";
  67.     } else {
  68.         $modconf = "/etc/modules.conf";
  69.     }
  70.     }
  71. }
  72.  
  73. my $res;
  74. my $dbg_file;
  75.  
  76. $dbg_file = "/dev/null";
  77.  
  78. # "-D" is for development/debugging only
  79. if ($ARGV[0] eq "-D") {
  80.     $dbg_file = "/tmp/ndiswrapper.dbg";
  81.     $confdir = "/tmp/ndiswrapper";
  82.     shift;
  83. }
  84.  
  85. open(DBG, "> $dbg_file") or die "couldn't open $dbg_file: $!";
  86.  
  87. if ($ARGV[0] eq "-i" and @ARGV == 2) {
  88.     $res = install($ARGV[1]);
  89. } elsif (($ARGV[0] eq "-a" or $ARGV[0] eq "-d") and @ARGV == 3) {
  90.     $res = device_driver_alias($ARGV[1], $ARGV[2]);
  91. } elsif (($ARGV[0] eq "-e" or $ARGV[0] eq "-r") and @ARGV == 2) {
  92.     $res = remove_driver($ARGV[1]);
  93. } elsif ($ARGV[0] eq "-l" and @ARGV == 1) {
  94.     $res = list_drivers();
  95. } elsif ($ARGV[0] eq "-m" and @ARGV == 1) {
  96.     $res = add_module_alias();
  97. } elsif ($ARGV[0] eq "-v" and @ARGV == 1) {
  98.     $res = check_version();
  99. } elsif ($ARGV[0] eq "-ma" and @ARGV == 1) {
  100.     $res = generate_module_device_map(0);
  101. } elsif ($ARGV[0] eq "-mi" and @ARGV == 1) {
  102.     $res = generate_module_device_map(1);
  103. } else {
  104.     usage();
  105. }
  106. close(DBG);
  107. exit($res);
  108.  
  109. sub usage() {
  110.     print "install/manage Windows drivers for ndiswrapper\n\n" .
  111.         "usage: ndiswrapper OPTION\n" .
  112.     "-i inffile       install driver described by 'inffile'\n" .
  113.     "-a devid driver  use installed 'driver' for 'devid' (dangerous)\n" .
  114.     "-r driver        remove 'driver'\n" .
  115.     "-l               list installed drivers\n" .
  116.     "-m               write configuration for modprobe\n" .
  117.     "-ma              write module alias configuration for all devices\n" .
  118.     "-mi              write module install configuration for all devices\n" .
  119.     "-v               report version information\n\n" .
  120.     "where 'devid' is either PCIID or USBID of the form XXXX:XXXX,\n" .
  121.       "as reported by 'lspci -n' or 'lsusb' for the card\n";
  122. }
  123.  
  124. sub remove_driver {
  125.     my $driver = shift;
  126.     if (!rmtree("$confdir/$driver", 0, 1)) {
  127.     warn "couldn't delete $confdir/$driver: $!\n";
  128.     }
  129.     return 0;
  130. }
  131.  
  132. sub abort {
  133.     remove_driver($driver_name);
  134.     exit 1;
  135. }
  136.  
  137. sub check_version {
  138.     my ($utils_version, $module_utils_version, $res);
  139.     $res = 0;
  140.     $utils_version = `loadndisdriver -v`;
  141.     chomp($utils_version);
  142.     $utils_version =~ s/^version: //;
  143.     if (length($utils_version) eq 0) {
  144.     printf "utils version is too old!\n";
  145.     $res = -1;
  146.     }
  147.     $module_utils_version = 0;
  148.     open(MODINFO, "modinfo ndiswrapper |");
  149.     while (my $line = <MODINFO>) {
  150.     if ($line =~ /utils_version:.*read only:\s([0-9\.]+)/) {
  151.         $module_utils_version = $1;
  152.         last;
  153.     }
  154.     }
  155.     if ($module_utils_version eq 0) {
  156.     printf "module version is too old!\n";
  157.     $res = -1;
  158.     } elsif ($utils_version ne $module_utils_version) {
  159.     printf "utils version '%s' is incompatible with utils version needed" .
  160.       " by driver ('%s')!\n", $utils_version, $module_utils_version;
  161.     $res = -1;
  162.     }
  163.     printf "utils version: '%s', utils version needed by module: '%s'\n",
  164.       $utils_version, $module_utils_version;
  165.     printf "module details:\n";
  166.     system("modinfo ndiswrapper | grep -E '^(version|vermagic|filename)'");
  167.  
  168.     if ($res) {
  169.     printf "\nYou may need to upgrade driver and/or utils to latest " .
  170.       "versions available at\n" .
  171.       "http://ndiswrapper.sourceforge.net\n";
  172.     }
  173.     return $res;
  174. }
  175.  
  176. sub install {
  177.     my $inf = shift;
  178.     chomp($inf);
  179.     $src_dir = dirname($inf);
  180.     $driver_name = lc(basename($inf));
  181.     unless ($driver_name =~ s/\.inf$//) {
  182.     die "install argument must be .inf file\n";
  183.     }
  184.  
  185.     if (! -d $confdir) {
  186.     mkdir($confdir) or die "couldn't create $confdir: $!";
  187.     }
  188.     (-d "$confdir/$driver_name") and
  189.       die "driver $driver_name is already installed\n";
  190.     read_sections($inf);
  191.     parse_section("Strings");
  192.     parse_section("Version");
  193.     parse_source_disks_files();
  194.     mkdir("$confdir/$driver_name") or
  195.       die "couldn't create $confdir/$driver_name: $!";
  196.     print "installing $driver_name ...\n";
  197.     parse_mfr();
  198.     copy_file(basename($inf), basename($inf));
  199.     create_fuzzy_conf($driver_name);
  200.     return 0;
  201. }
  202.  
  203. # return lines in section
  204. sub get_section {
  205.     my $name = shift;
  206.     foreach my $key (keys %sections) {
  207.     if (lc($key) eq lc($name)) {
  208.         printf DBG "section: $key\n";
  209.         return \@{$sections{$key}};
  210.     }
  211.     }
  212.     printf DBG "couldn't find section \"$name\"\n";
  213.     return 0;
  214. }
  215.  
  216. # load inf and split into different sections.
  217. sub read_sections {
  218.     my $filename = shift;
  219.     open(INF, $filename) or die "couldn't open $filename: $!";
  220.  
  221.     my $name = "none";
  222.     @{$sections{$name}} = ();
  223.     while (my $line = <INF>) {
  224.     # convert from unicode
  225.     $line =~ s/\xff\xfe//;
  226.     $line =~ s/\0//g;
  227.  
  228.     chomp($line);
  229.     $line = trim($line);
  230.     next if ($line =~ /^$/);
  231.     if ($line =~ /^\[(.+)\]/) {
  232.         $name = $1;
  233.         @{$sections{$name}} = ();
  234.     } else {
  235.         push(@{$sections{$name}}, $line);
  236.     }
  237.     }
  238.     close(INF);
  239.     foreach $name (keys %sections) {
  240.     printf DBG "section: %s\n", $name;
  241.     foreach my $line (@{$sections{$name}}) {
  242.         printf DBG "%s: %s\n", $name, $line;
  243.     }
  244.     }
  245. }
  246.  
  247. sub parse_section {
  248.     my $name = shift;
  249.     my $lines = get_section($name);
  250.     if (!$lines) {
  251.     return;
  252.     }
  253.     $parsed_sections{$name} = ();
  254.     foreach my $line (@{$lines}) {
  255.     (my $key, my $val) = parse_key_value($line);
  256.     if ($key) {
  257.         $val = strip_quotes($val);
  258.         $parsed_sections{$name}->{$key} = $val;
  259.         printf DBG "$name: %s = %s\n", $key, $val;
  260.     }
  261.     }
  262. }
  263.  
  264. sub parse_mfr() {
  265.     my $lines = get_section("Manufacturer");
  266.     $lines or die "couldn't get manufacturer section - " .
  267.       "installation may be incomplete\n";
  268.     foreach  my $line (@{$lines}) {
  269.     my ($strkey, $val) = parse_key_value($line);
  270.     if ($strkey) {
  271.         my ($models, @targets) = split(",", $val);
  272.         if ($models) {
  273.         printf DBG "mfr: %s, %s\n", $line, $models;
  274.         my $target = choose_target_os(@targets);
  275.         printf DBG "target: '%s'\n", $target;
  276.         parse_models($models, $target);
  277.         }
  278.     }
  279.     }
  280. }
  281.  
  282. sub parse_models {
  283.     my ($models, $target) = @_;
  284.     printf DBG "models: target: '%s'.'%s'\n", $models, $target;
  285.     my $lines = get_target_os_section($models, $target);
  286.     if (!$lines) {
  287.     warn "couldn't find models section \"$models\" -\n" .
  288.       "installation may be incomplete\n";
  289.     return -1;
  290.     }
  291.     foreach my $line (@{$lines}) {
  292.     $line = del_comment($line);
  293.     next if (length($line) eq 0);
  294.     (my $dev_desc, my $val) = parse_key_value($line);
  295.     my @fields = split(",", $val);
  296.     if (@fields le 1) {
  297.         printf "couldn't find install directive: %s\n", $line;
  298.         next;
  299.     }
  300.     my $section = trim($fields[0]);
  301.     my $hwid = trim($fields[1]);
  302.     if ($hwid =~ /^%.+%$/) {
  303.         $hwid = get_string_value($hwid);
  304.     }
  305.     # TODO: deal with compatible IDs as hwid?
  306.     my ($bus_type, $vendor, $device, $subvendor, $subdevice) =
  307.       parse_hwid($hwid);
  308.     next if (!$vendor);
  309.     printf DBG "models: %s, %s, %s\n", $section, $hwid, $vendor;
  310.     parse_install($section, $target, $bus_type, $vendor, $device,
  311.               $subvendor, $subdevice);
  312.     }
  313. }
  314.  
  315. sub parse_install {
  316.     my ($section, $target, $bus_type, $vendor, $device,
  317.     $subvendor, $subdevice) = @_;
  318.     my $lines = get_target_os_section($section, $target);
  319.     if (!$lines) {
  320.     warn "couldn't find install section \"$section\" -\n" .
  321.       "installation may be incomplete\n";
  322.     return -1;
  323.     }
  324.  
  325.     my $filename = "$vendor:$device";
  326.     if ($subvendor) {
  327.     $filename .= ":$subvendor:$subdevice"
  328.     }
  329.     $filename .= sprintf(".%X.conf", $bus_type);
  330.  
  331.     my (@addregs, @copyfiles);
  332.     foreach my $line (@{$lines}) {
  333.     $line =~ s/^;\s*//;
  334.     $line = trim(del_comment($line));
  335.     my ($key, $val) = parse_key_value($line);
  336.     my @array;
  337.     if ($key) {
  338.         if (lc($key) eq "addreg") {
  339.         @array = split(",", $val);
  340.         foreach my $reg (@array) {
  341.             push @addregs, trim($reg);
  342.         }
  343.         } elsif (lc($key) eq "copyfiles") {
  344.         printf DBG "copyfiles: %s\n", $val;
  345.         @array = split(",", $val);
  346.         foreach my $copy_file_dirs (@array) {
  347.             my @copy_sec = split(",", $copy_file_dirs);
  348.             foreach my $file (@copy_sec) {
  349.             push @copyfiles, trim($file);
  350.             }
  351.         }
  352.         } elsif (lc($key) eq "bustype") {
  353.         printf DBG "bustype: %s\n", $val;
  354.         $bus_type = $val;
  355.         }
  356.     }
  357.     }
  358.  
  359.     open(CONF, ">$confdir/$driver_name/$filename") or
  360.       die "couldn't create file $confdir/$driver_name/$filename: $!";
  361.  
  362.     printf CONF "sys_files|";
  363.     foreach my $file (@copyfiles) {
  364.     parse_copy_file($file);
  365.     }
  366.     printf CONF "\n";
  367.  
  368.     my $version = get_section_value("Version", "DriverVer");
  369.     my $provider = get_section_value("Version", "Provider");
  370.     my $classguid = get_section_value("Version", "ClassGUID");
  371.     my $providerstring = trim(strip_quotes(get_string_value(trim($provider))));
  372.     $classguid =~ s/^\s*{//;
  373.     $classguid =~ s/}\s*$//;
  374.  
  375.     printf CONF "NdisVersion|0x50001\n";
  376.     printf CONF "Environment|1\n";
  377.     printf CONF "class_guid|%s\n", $classguid;
  378.     printf CONF "driver_version|%s,%s\n", $providerstring, $version;
  379.     printf CONF "BusType|%s\n", $bus_type;
  380.     printf CONF "SlotNumber|01\n";
  381.     printf CONF "NetCfgInstanceId|{28022A01-1234-5678-ABCDE-123813291A00}\n";
  382.     printf CONF "\n";
  383.     close(CONF);
  384.  
  385.     open(CONF, "|sort|uniq >>$confdir/$driver_name/$filename") or
  386.       die "couldn't create file $confdir/$driver_name/$filename: $!";
  387.  
  388.     foreach my $reg (@addregs) {
  389.     parse_registry($reg);
  390.     }
  391.     close(CONF);
  392. }
  393.  
  394. sub parse_registry {
  395.     my ($reg, $conf) = @_;
  396.     my $lines = get_section($reg);
  397.     if (!$lines) {
  398.     warn "couldn't find section \"$reg\" -\n" .
  399.       "installation may be incomplete\n";
  400.     return -1;
  401.     }
  402.  
  403.     my $driver_desc = 0;
  404.     foreach my $line (@{$lines}) {
  405.     $line = del_comment($line);
  406.     my @fields = split(",", $line);
  407.     next if (@fields lt 4);
  408.     my $value;
  409.     my $param = trim($fields[1]);
  410.     if ($param =~ /^ndi\\/i) {
  411.         if ($param =~ /^ndi\\params\\(.+)/i) {
  412.         $param = strip_quotes(trim($1));
  413.         $param =~ s/\\.*$//;
  414.         next if (lc(trim($fields[2])) ne "default");
  415.         $value = strip_quotes(trim($fields[4]));
  416.         } else {
  417.         printf DBG "ignoring parameter $line\n";
  418.         next;
  419.         }
  420.     } else {
  421.         $param = strip_quotes(trim($fields[2]));
  422.         next if (length($param) eq 0);
  423.         $value = strip_quotes(trim($fields[4]));
  424.     }
  425.     $value = get_string_value($value);
  426.     if (length($param) gt 0) {
  427.         if ($param_fixlist{"$param|$value"}) {
  428.         my $orig_value = $value;
  429.         $value = $param_fixlist{"$param|$value"};
  430.         printf "forcing parameter $param from $orig_value to $value\n";
  431.         }
  432.         printf CONF "%s|%s\n", $param, $value;
  433.         if ($param =~ /^DriverDesc$/) {
  434.         $driver_desc = 1;
  435.         }
  436.     }
  437.     }
  438.     if ($driver_desc == 0) {
  439.     printf CONF "DriverDesc|NDIS Network Adapter\n";
  440.     }
  441. }
  442.  
  443. sub parse_copy_file {
  444.     my $copy_name = shift;
  445.  
  446.     if ($copy_name =~ /^\@/) {
  447.     $copy_name =~ s/^\@//;
  448.     $copy_name = trim($copy_name);
  449.     if (valid_copy_file_name($copy_name)) {
  450.         return copy_file($copy_name, $copy_name);
  451.     }
  452.     }
  453.  
  454.     my $lines = get_section($copy_name);
  455.     if (!$lines) {
  456.     warn "couldn't find section \"$copy_name\" -\n" .
  457.       "installation may be incomplete\n";
  458.     return -1;
  459.     }
  460.     foreach my $line (@{$lines}) {
  461.     $line = trim($line);
  462.  
  463.     # some inf files have file names commented out; get file names from them
  464.     $line =~ s/^\s*;//;
  465.     my @files = split(",", $line);
  466.     if (@files == 0) {
  467.         printf DBG "copyfiles section $copy_name has no files\n";
  468.         return -1;
  469.     }
  470.     my $src, my $dst;
  471.     if (@files > 1 and length(trim($files[1])) > 0) {
  472.         $src = $files[1];
  473.         if (length(trim($files[0])) > 0) {
  474.         $dst = $files[0];
  475.         } else {
  476.         $dst = $src;
  477.         }
  478.     } else {
  479.         $src = $files[0];
  480.         $dst = $src;
  481.     }
  482.     $src =~ s/^.*\\//;
  483.     $dst =~ s/^.*\\//;
  484.     printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
  485.     $src = trim(del_comment($src));
  486.     next if (length($src) eq 0);
  487.     if (valid_copy_file_name($src)) {
  488.         $dst = trim(del_comment($dst));
  489.         printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
  490.         copy_file($src, $dst);
  491.     } else {
  492.         printf DBG "invalid file '%s' ignored\n", $src;
  493.     }
  494.     }
  495.     return 0;
  496. }
  497.  
  498. sub parse_hwid {
  499.     my $hwid = uc(shift);
  500.     if ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)&SUBSYS_(\w{4})(\S{4})/) {
  501.     return ($WRAP_PCI_BUS, $2, $3, $4, $5);
  502.     } elsif ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)/) {
  503.     return ($WRAP_PCI_BUS, $2, $3, 0, 0);
  504.     } elsif ($hwid =~ /(USB\\)?VID_(\w+)&PID_(\w+)/) {
  505.     return ($WRAP_USB_BUS, $2, $3, 0, 0);
  506.     } else {
  507.     return 0;
  508.     }
  509. }
  510.  
  511. sub parse_key_value {
  512.     my $line = shift;
  513.  
  514.     $line = del_comment($line);
  515.     if ($line =~ /([^=]+)=(.+)/) {
  516.     return (trim($1), trim($2));
  517.     } else {
  518.     return 0;
  519.     }
  520. }
  521.  
  522. sub choose_target_os {
  523.     my @targets = @_;
  524.     my $arch = `uname -m`;
  525.     chomp($arch);
  526.     printf DBG "arch: %s\n", $arch;
  527.     if ($arch =~ /64$/) {
  528.     $arch = "amd64";
  529.     } else {
  530.     $arch = "x86";
  531.     }
  532.     printf DBG "arch: %s\n", $arch;
  533.     my @prefs = ("NT($arch)\.5\.1", "NT($arch)\.5", "NT($arch)",
  534.          "NT\.5\.1", "NT\.5", "NT");
  535.     foreach my $pref (@prefs) {
  536.     foreach my $target (@targets) {
  537.         $target = trim($target);
  538.         printf DBG "target: '%s', pref: '%s'\n", $target, $pref;
  539.         if ($target =~ /NT((amd64)|(x86))/i) {
  540.         printf DBG "target arch: '%s'\n", $1;
  541.         next if ($1 !~ /$arch/i);
  542.         }
  543.         if ($target =~ /$pref/i) {
  544.         return $target;
  545.         }
  546.     }
  547.     }
  548.     return "";
  549. }
  550.  
  551. sub get_target_os_section {
  552.     my ($section, $target) = @_;
  553.     my $lines;
  554.  
  555.     chomp($section);
  556.     $section =~ s/^\s*"\s*//;
  557.     $section =~ s/\s*"\s*$//;
  558.     printf DBG "section: \"%s\", target: \"%s\"\n", $section, $target;
  559.  
  560.     if (length($target) gt 0) {
  561.     $lines = get_section($section . "." . $target);
  562.     return $lines if ($lines);
  563.     }
  564.  
  565.     my $arch = `uname -m`;
  566.     chomp($arch);
  567.     printf DBG "arch: %s\n", $arch;
  568.     if ($arch =~ /64$/) {
  569.     $arch = "AMD64";
  570.     } else {
  571.     $arch = "X86";
  572.     }
  573.     printf DBG "arch: %s\n", $arch;
  574.  
  575.     my @prefs = ("NT$arch.5.1", "NT$arch.5", "NT$arch",
  576.          "NT.5.1", "NT.5", "NT");
  577.     foreach my $pref (@prefs) {
  578.     $lines = get_section($section . "." . $pref);
  579.     return $lines if ($lines);
  580.     }
  581.     $lines = get_section($section);
  582.     return $lines if ($lines);
  583.  
  584.     printf DBG "couldn't find section \"$section\" for \"$arch\"\n";
  585.     return 0;
  586. }
  587.  
  588. sub get_section_value {
  589.     (my $section, my $name) = @_;
  590.     return $parsed_sections{$section}->{$name};
  591. }
  592.  
  593. sub get_string_value {
  594.     my $key = shift;
  595.     if ($key =~ /%(.+)%/) {
  596.     $key = $1;
  597.     return get_section_value("Strings", $key);
  598.     } else {
  599.     return $key;
  600.     }
  601. }
  602.  
  603. sub copy_file {
  604.     my ($src, $dst) = @_;
  605.  
  606.     # ignore files not needed
  607.     return 0 if (lc($src) =~ /\.((exe)|(dll)|(cpl)|(hlp))$/);
  608.     my $real_file = get_file($src);
  609.     if (length($real_file) gt 0) {
  610.     $dst = lc($dst);
  611.     printf DBG "copying \"$src_dir/$real_file\" to " .
  612.       "\"$confdir/$driver_name/$dst\"\n";
  613.     copy("$src_dir/$real_file", "$confdir/$driver_name/$dst") or
  614.       warn "couldn't copy \"$src_dir/$real_file\" to " .
  615.         "\"$confdir/$driver_name\": $! -\n" .
  616.           "installation may be incomplete\n";
  617.     printf DBG "chmod: $confdir/$driver_name/$dst\n";
  618.     chmod(0644, "$confdir/$driver_name/$dst");
  619.     if ($dst =~ /\.sys$/) {
  620.         printf CONF "%s ", $dst;
  621.     }
  622.     } else {
  623.     warn "couldn't find \"$src\" in \"$src_dir\"; make sure " .
  624.       "all driver files, including .inf, .sys (and any firmware files) " .
  625.         "are in \"$src_dir\" -\n" .
  626.           "installation may be incomplete\n";
  627.     }
  628. }
  629.  
  630. # for conf files with subvendor and subdevice, create conf files with just
  631. # vendor and device
  632. sub create_fuzzy_conf {
  633.     my $driver = shift;
  634.     my $cwd = cwd();
  635.     chdir("$confdir/$driver") or die "couldn't chdir to $confdir/$driver: $!";
  636.     open(LS, "ls -1 . |") or die "couldn't open $confdir/$driver: $!";
  637.     while (my $file = <LS>) {
  638.     chomp($file);
  639.     if ($file =~ /$re_sub_dev_conf/) {
  640.         my $fuzzy_file = "$1:$2.$5.conf";
  641.         printf DBG "file: $file, fuzzy file: $fuzzy_file\n";
  642.         if (! -e "$confdir/$driver/$fuzzy_file") {
  643.         symlink("$file", "$fuzzy_file") or
  644.           warn "couldn't link $confdir/$driver/$file " .
  645.             "to $confdir/$driver/$fuzzy_file: $!\n";
  646.         }
  647.     }
  648.     }
  649.     close(LS);
  650.     chdir($cwd) or warn "couldn't chdir to $cwd: $!";
  651.     return 0;
  652. }
  653.  
  654. # find a file in a case-insensitive way.
  655. sub get_file {
  656.     my $file = lc(shift);
  657.     if (opendir(DIR, "$src_dir")) {
  658.     my @allfiles = readdir(DIR);
  659.     foreach my $real_file (@allfiles) {
  660.         if (lc($real_file) eq $file) {
  661.         closedir(DIR);
  662.         return $real_file;
  663.         }
  664.     }
  665.     closedir(DIR);
  666.     } else {
  667.     warn "couldn't open \"$src_dir\": $! -\n" .
  668.       "installation may be incomplete\n";
  669.     }
  670.     return "";
  671. }
  672.  
  673. sub strip_quotes {
  674.     my $s = shift;
  675.     $s =~ s/"(.*)"/$1/;
  676.     return $s;
  677. }
  678.  
  679. sub del_comment {
  680.     my $s = shift;
  681.     $s =~ s/;.*//;
  682.     return $s;
  683. }
  684.  
  685. # remove whitsepace at front and end.
  686. sub trim {
  687.     my $s = shift;
  688.     $s =~ s/^\s*//;
  689.     $s =~ s/\s*$//;
  690.     return $s;
  691. }
  692.  
  693. sub valid_copy_file_name {
  694.     my $file = shift;
  695.     $file = lc($file);
  696.     printf DBG "file name: %s\n", $file;
  697.     foreach my $disk_file (@source_disks_files) {
  698.     return 1 if ($file eq $disk_file);
  699.     }
  700.     # some inf files may not have SourceDisksFiles section, so use
  701.     # known file names
  702.     return 1 if ($file =~ /\.((sys)|(bin)|(out))$/);
  703.     return 0;
  704. }
  705.  
  706. sub parse_source_disks_files {
  707.     my $lines = get_source_disks_files();
  708.     if ($lines) {
  709.     foreach my $line (@{$lines}) {
  710.         $line = del_comment($line);
  711.         next if (length($line) eq 0);
  712.         my @file = split("=", $line);
  713.         next if (@file eq 0 or length($file[0] eq 0));
  714.         printf DBG "source disk file: \"%s\"\n", trim($file[0]);
  715.         push (@source_disks_files, lc(trim($file[0])));
  716.     }
  717.     } else {
  718.     warn "couldn't find SourceDisksFiles section - " .
  719.       "continuing anyway...\n";
  720.     }
  721. }
  722.  
  723. sub get_source_disks_files {
  724.     my $arch = `uname -m`;
  725.     chomp($arch);
  726.     if ($arch =~ /64$/) {
  727.     $arch = "AMD64";
  728.     } else {
  729.     $arch = "X86";
  730.     }
  731.  
  732.     my $lines = get_section("SourceDisksFiles." . $arch);
  733.     return $lines if ($lines);
  734.  
  735.     $lines = get_section("SourceDisksFiles");
  736.     return $lines if ($lines);
  737.  
  738.     return 0;
  739. }
  740.  
  741. sub device_driver_alias {
  742.     my ($devid, $driver) = @_;
  743.     my $done = 0;
  744.  
  745.     $devid = uc($devid);
  746.     if (!($devid =~ /^$re_dev_id:$re_dev_id$/)) {
  747.     printf "'$devid' is not a valid device ID\n";
  748.     return 1;
  749.     }
  750.     open(LS, "ls -1 $confdir/$driver/ |") or
  751.       die "couldn't open $confdir/$driver: $!";
  752.  
  753.     while (my $f = <LS>) {
  754.     chomp($f);
  755.     if ($f =~ /\.([[:xdigit:]]+)\.conf$/) {
  756.         if (stat("$confdir/$driver/$devid.$1.conf")) {
  757.         printf "Driver '$driver' is already used for '$devid'\n";
  758.         $done = 1;
  759.         last;
  760.         }
  761.         if (symlink("$f", "$confdir/$driver/$devid.$1.conf")) {
  762.         printf "WARNING: Driver '$driver' will be used for '$devid'\n" .
  763.           "This is safe _only_ if driver $driver is meant for " .
  764.             "chip in device $devid\n";
  765.         $done = 1;
  766.         last;
  767.         } else {
  768.         warn "couldn't create symlink for \"$f\": $! -\n" .
  769.           "installation may be incomplete\n";
  770.         }
  771.     }
  772.     }
  773.     close(LS);
  774.     if ($done == 0) {
  775.     printf "driver '$driver' is not installed (properly)!\n";
  776.     return 1;
  777.     }
  778.     return 0;
  779. }
  780.  
  781. sub generate_module_device_map {
  782.     my $mode = shift;
  783.     my ($vendor, $device, $subvendor, $subdevice, $bustype, $busid);
  784.  
  785.     my $device_map;
  786.     if (-d "/etc/modprobe.d") {
  787.     $device_map = $modconf;
  788.     } elsif (-d "/etc/modules.d") {
  789.     $device_map = "/etc/modules.d/ndiswrapper";
  790.     } else {
  791.     $device_map = "/etc/ndiswrapper/ndiswrapper";
  792.     }
  793.  
  794.     open(DEVMAP, "| sort >$device_map") or
  795.       die "couldn't create modules alias file $device_map: $!";
  796.     open(LS, "ls -1 $confdir|") or
  797.       die "couldn't open $confdir: $!";
  798.     while (my $driver = <LS>) {
  799.     chomp($driver);
  800.     my $stat = (stat("$confdir/$driver"))[2];
  801.     if (S_ISDIR($stat)) {
  802.         open(LS2, "ls -1 $confdir/$driver/ |") or
  803.           die "couldn't open $confdir/$driver: $!";
  804.         while (my $file = <LS2>) {
  805.         chomp ($file);
  806.         if ($file =~ /\.conf$/) {
  807.             if ($file =~ /^$re_sub_dev_conf$/) {
  808.             ($vendor, $device, $subvendor, $subdevice, $busid) =
  809.               (uc($1), uc($2), "0000$3", "0000$4", hex($5));
  810.             } elsif ($file =~ /^$re_dev_conf$/) {
  811.             ($vendor, $device, $subvendor, $subdevice, $busid) =
  812.               (uc($1), uc($2), "*", "*", hex($3));
  813.             }
  814.             my $devstring;
  815.             if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
  816.             $devstring = sprintf("usb:v%sp%sd*dc*dsc*dp*ic*isc*ip*",
  817.                          $vendor, $device);
  818.             } elsif ($busid eq $WRAP_PCI_BUS) {
  819.             $devstring = sprintf("pci:v0000%sd0000%ssv%ssd%sbc*sc*i*",
  820.                          $vendor, $device, $subvendor,
  821.                          $subdevice);
  822.             } else {
  823.             warn "wrong bustype ($busid) for " .
  824.               "configuration file $file - ignoring it\n";
  825.             next;
  826.             }
  827.             if ($mode == 0) {
  828.             printf DEVMAP "alias %s ndiswrapper\n", $devstring;
  829.             } else {
  830.             printf DEVMAP "install %s /sbin/modprobe ndiswrapper\n",
  831.               $devstring;
  832.             }
  833.         }
  834.         }
  835.         close(LS2);
  836.     }
  837.     }
  838.     close(LS);
  839.     close(DEVMAP);
  840.  
  841.     printf "module configuration information is stored in $device_map\n";
  842.     return 0;
  843. }
  844.  
  845. sub list_drivers {
  846.     my $cards = get_cards();
  847.  
  848.     open(LS, "ls -1 $confdir|") or die "couldn't open $confdir: $!";
  849.     while (my $driver = <LS>) {
  850.     chomp($driver);
  851.     if (-e "$confdir/$driver") {
  852.         printf "%s : %s\n", $driver, install_status($cards, $driver);
  853.     }
  854.     }
  855.     close(LS);
  856.     return 0;
  857. }
  858.  
  859. sub add_module_alias {
  860.     my $alias = 0;
  861.  
  862.     open(MODPROBE, "modprobe -c|") or die "couldn't run modprobe: $!";
  863.     while (my $line = <MODPROBE>) {
  864.     if ($line =~ /^alias\s.+\sndiswrapper/) {
  865.         printf "module configuration already contains alias directive\n\n";
  866.         $alias = 1;
  867.     } elsif ($line =~ /^install\s.*ndiswrapper/) {
  868.         warn "module configuration contains directive $line;" .
  869.           "you should delete that";
  870.     } elsif ($line =~ /^post-install\s+ndiswrapper/) {
  871.         warn "module configuration contains directive $line;" .
  872.           "you should delete that";
  873.     }
  874.     }
  875.     close(MODPROBE);
  876.  
  877.     if ($alias) {
  878.     return 0;
  879.     }
  880.  
  881.     printf "adding \"alias wlan0 ndiswrapper\" to $modconf ...\n";
  882.     system("echo \"alias wlan0 ndiswrapper\" >>$modconf") == 0 or
  883.       die "couldn't add module alias: $!";
  884.     if (-x "/sbin/update-modules") {
  885.     system("/sbin/update-modules");
  886.     }
  887.     return 0;
  888. }
  889.  
  890. sub get_cards {
  891. #01:00.0 Class 0300: 1002:4c66 (rev 01)
  892. #        Subsystem: 1043:1732
  893.     my @cards = ();
  894.     if (open(LSPCI, "lspci -vn|")) {
  895.     my $card;
  896.     while (my $line = <LSPCI>) {
  897.         if ($line =~ /^[0-9a-f]+.+\s$re_dev_id:$re_dev_id/) {
  898.         $card = {vendor => uc($1), device => uc($2)};
  899.         printf DBG "card: %s, %s\n", $1, $2;
  900.         } elsif ($line =~ /.+Subsystem:\s$re_dev_id:$re_dev_id/) {
  901.         $card->{subvendor} = uc($1);
  902.         $card->{subdevice} = uc($2);
  903.         printf DBG "sub: %s, %s\n", $1, $2;
  904.         push(@cards, $card);
  905.         }
  906.     }
  907.     close(LSPCI);
  908.     }
  909.  
  910.     if (open(LSUSB, "lsusb |")) {
  911.     my $card;
  912.     while (my $line = <LSUSB>) {
  913.         if ($line =~ /.+: ID\s$re_dev_id:$re_dev_id/) {
  914.         $card = {vendor => uc($1), device => uc($2)};
  915.         push(@cards, $card);
  916.         }
  917.     }
  918.     close(LSUSB);
  919.     }
  920.     return \@cards;
  921. }
  922.  
  923. sub install_status {
  924.     my ($cards, $driver) = @_;
  925.  
  926.     if (!$cards or !$driver) {
  927.     return;
  928.     }
  929.  
  930.     my ($sys, $conf, $inf);
  931.     my ($vendor, $device, $subvendor, $subdevice, $busid, $ret);
  932.  
  933.     $sys = $conf = $inf = 0;
  934.     open(LS2, "ls -1 $confdir/$driver|") or
  935.       die "couldn't open $confdir/$driver: $!";
  936.     while (my $file = <LS2>) {
  937.     chomp($file);
  938.     if ($file =~ /\.sys$/) {
  939.         $sys = 1;
  940.     } elsif ($file =~ /\.inf$/) {
  941.         $inf = 1;
  942.     } elsif ($file =~ /^$re_sub_dev_conf$/) {
  943.         $busid = hex($5);
  944.         $conf = 1 if ($busid eq $WRAP_PCI_BUS);
  945.     } elsif ($file =~ /^$re_dev_conf$/) {
  946.         $busid = hex($3);
  947.         $conf = 1 if ($busid eq $WRAP_USB_BUS or $busid eq 0 or
  948.               $busid eq $WRAP_PCI_BUS);
  949.     }
  950.     }
  951.     close(LS2);
  952.     printf DBG "status: $sys, $inf, $conf\n";
  953.     if ($sys eq 0 or $inf eq 0 or $conf eq 0) {
  954.     $ret = "invalid driver!";
  955.     return $ret;
  956.     }
  957.     $ret = "driver installed";
  958.     open(LS2, "ls -1 $confdir/$driver|") or
  959.       die "couldn't open $confdir/$driver: $!";
  960.  
  961.     while (my $file = <LS2>) {
  962.     chomp($file);
  963.     next if ($file !~ /\.conf$/);
  964.     $conf = 0;
  965.     if ($file =~ /^$re_sub_dev_conf$/) {
  966.         ($vendor, $device, $subvendor, $subdevice, $busid) =
  967.           (uc($1), uc($2), uc($3), uc($4), hex($5));
  968.         $conf = 1;
  969.         foreach my $card (@{$cards}) {
  970.         if ($card->{vendor} eq $vendor and
  971.             $card->{device} eq $device and
  972.             $card->{subvendor} eq $subvendor and
  973.             $card->{subdevice} eq $subdevice and
  974.             $busid eq $WRAP_PCI_BUS) {
  975.             $ret .= "\n\tdevice ($vendor:$device" .
  976.               ":$subvendor:$subdevice) present";
  977.             $conf = 2;
  978.             last;
  979.         }
  980.         }
  981.     } elsif ($file =~ /^$re_dev_conf/) {
  982.         ($vendor, $device, $subvendor, $subdevice, $busid) =
  983.           (uc($1), uc($2), "\\*", "\\*", hex($3));
  984.         $conf = 1;
  985.         foreach my $card (@{$cards}) {
  986.         if ($card->{vendor} eq $vendor and
  987.             $card->{device} eq $device and
  988.             ($busid eq $WRAP_USB_BUS or $busid eq 0 or
  989.              $busid eq $WRAP_PCI_BUS)) {
  990.             $ret .= "\n\tdevice ($vendor:$device) present";
  991.             $conf = 2;
  992.             last;
  993.         }
  994.         }
  995.     }
  996.     next if ($conf le 1);
  997.     # find if kernel knows of an alternate driver for this device
  998.     my $devstring;
  999.     if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
  1000.         $devstring = sprintf("usb:v%sp%sd", $vendor, $device);
  1001.     } elsif ($busid eq $WRAP_PCI_BUS) {
  1002.         $devstring = sprintf("pci:v0000%sd0000%ssv", $vendor, $device);
  1003.     } else {
  1004.         next;
  1005.     }
  1006.     open(MODPROBE, "modprobe -c|") or next;
  1007.     while (my $line = <MODPROBE>) {
  1008.         my $alt;
  1009.         chomp($line);
  1010.         next if $line !~ /$devstring/;
  1011.         $alt = (split(' ', $line))[-1];
  1012.         chomp($alt);
  1013.         if (length($alt) gt 0 and $alt ne "ndiswrapper") {
  1014.         $ret .= " (alternate driver: $alt)";
  1015.         last;
  1016.         }
  1017.     }
  1018.     close(MODPROBE);
  1019.     }
  1020.     close(LS2);
  1021.     printf DBG "driver: $driver, $ret\n";
  1022.     return $ret;
  1023. }
  1024.  
  1025. ## Local Variables: ##
  1026. ## cperl-indent-level: 4 ##
  1027. ## End: ##
  1028.